/* test preprocess and postprocess using test cases here:
 * http://read.pudn.com/downloads134/ebook/572228/M309_Mifare&Security_V1.pdf
 */

#include <string.h>
#include <stdint.h>
#include "../mifare/mifare.h"
#include "../mifare/mifare_crypto.h"
#include "../mifare/mifare_key.h"
#include "test_general.h"

void test_mifare_crypto_des_no_offset(void)
{
  mifare_tag tag;
  
  
  uint8_t PCD_RndA[16] = {0};
  uint8_t PICC_RndB[16] = {0};
  
    
  uint8_t message[47] = {
    0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
    0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
    0x77, 0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 
    0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22,
    0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 
    0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77
  };
  
  uint8_t expected_enciphered_data[56] = {
    0xCD, 0x72, 0xDF, 0xC6, 0xE6, 0xD0, 0x40, 0xA4,
    0x81, 0xD6, 0xBD, 0xED, 0xB6, 0xEA, 0x5C, 0xCC, 
    0xEE, 0xC8, 0x21, 0x93, 0xB6, 0x8E, 0x92, 0x21,
    0xD8, 0xC1, 0xCD, 0x7C, 0x5C, 0x02, 0x02, 0x6C,
    0x7E, 0xE2, 0x98, 0xF5, 0xF0, 0xE3, 0x39, 0x6C,
    0xE4, 0x6A, 0x52, 0xB4, 0x2B, 0xB4, 0xC2, 0xF0,
    0x3A, 0x9C, 0x83, 0xBA, 0x0D, 0x83, 0x84, 0x67
  };
  uint8_t message_status[48] = {0};
  uint8_t enciphered_data_status[57] ={0};
  
  size_t nbytes = sizeof(message);
  ssize_t nbytes2;
  mifare_desfire_key key;
  uint8_t *enciphered_data, *deciphered_data;
  
  MifareTagInit(&tag);
  key.type = T_3DES;
  
  tag.authentication_scheme = AS_LEGACY;
  memset(tag.ivect, 0, MAX_CRYPTO_BLOCK_SIZE); 
  
  MifareSessionKeyNew(&tag.session_key, PCD_RndA, PICC_RndB, &key);
  
  
  enciphered_data = MifareCryptoPreprocessData(&tag, message, &nbytes,
                             0, MDCM_ENCIPHERED | ENC_COMMAND);
  
  assert_equal_memory(enciphered_data, nbytes, expected_enciphered_data, 56,
                      "CryptoPreprocess: DES encipher failed 1");
  
  
  nbytes2 = 57;
  memcpy(enciphered_data_status, enciphered_data, 56);
  deciphered_data = MifareCryptoPostprocessData (&tag, enciphered_data_status,
                                                 &nbytes2, MDCM_ENCIPHERED);
  
  memcpy(message_status, message, 47);
  assert_equal_memory(deciphered_data, nbytes2, message_status, 48,
                      "CryptoPostprocess: DES decipher failed");
}


void test_mifare_crypto_des_w_offset(void)
{
  mifare_tag tag;
  
  uint8_t PCD_RndA[16] = {0};
  uint8_t PICC_RndB[16] = {0};
  
    
  uint8_t message[55] = {
    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,  /* command + headers */
    0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
    0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
    0x77, 0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 
    0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22,
    0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 
    0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77
  };
  
  uint8_t expected_enciphered_data[64] = {
    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
    0xCD, 0x72, 0xDF, 0xC6, 0xE6, 0xD0, 0x40, 0xA4,
    0x81, 0xD6, 0xBD, 0xED, 0xB6, 0xEA, 0x5C, 0xCC, 
    0xEE, 0xC8, 0x21, 0x93, 0xB6, 0x8E, 0x92, 0x21,
    0xD8, 0xC1, 0xCD, 0x7C, 0x5C, 0x02, 0x02, 0x6C,
    0x7E, 0xE2, 0x98, 0xF5, 0xF0, 0xE3, 0x39, 0x6C,
    0xE4, 0x6A, 0x52, 0xB4, 0x2B, 0xB4, 0xC2, 0xF0,
    0x3A, 0x9C, 0x83, 0xBA, 0x0D, 0x83, 0x84, 0x67
  };
  
  
  size_t nbytes = sizeof(message);
  mifare_desfire_key key;
  uint8_t *enciphered_data;
  MifareTagInit(&tag);
  key.type = T_3DES;
  
  tag.authentication_scheme = AS_LEGACY;
  memset(tag.ivect, 0, MAX_CRYPTO_BLOCK_SIZE); 
  
  MifareSessionKeyNew(&tag.session_key, PCD_RndA, PICC_RndB, &key);
  
  
  enciphered_data = MifareCryptoPreprocessData(&tag, message, &nbytes,
                             8, MDCM_ENCIPHERED | ENC_COMMAND);
  
  assert_equal_memory(enciphered_data, nbytes, expected_enciphered_data, 64,
                      "CryptoPreprocess: DES encipher failed 2");
}




void test_mifare_crypto(void)
{
  test_mifare_crypto_des_no_offset(); /* MDCM_ENCIPHERED | ENC_COMMAND */
  test_mifare_crypto_des_w_offset();  /* MDCM_ENCIPHERED | ENC_COMMAND */
}
